Classes, Objects, and Memory Management in C++

📘 Classes, Objects, and Memory Management in C++

C++ is widely regarded as one of the most powerful programming languages ever created. It blends procedural programming (from C) with object-oriented programming (OOP) features, giving developers flexibility and control over performance and structure.
At the heart of C++ lies the concept of classes and objects, which allow programmers to model real-world entities inside a program. Alongside these, memory management ensures that objects are created, used, and destroyed efficiently, keeping programs optimized.

1. Concept of a Class and Object
The two fundamental building blocks of OOP in C++ are classes and objects.
Class → A blueprint or template.
Object → An instance of a class.
Think of a class as the design of a car, and an object as an actual car built using that design.

1.1 Defining a Class
In C++, a class groups data members (variables) and member functions (methods) into a single unit.
Syntax:
class ClassName {
    // Access specifier
    private:
        // data members
    public:
        // member functions
};

Example:
#include <iostream>
using namespace std;
class Student {
public:
    string name;
    int age;
    void display() {
        cout << "Name: " << name << ", Age: " << age << endl;
    }
};

1.2 Creating Objects
Once a class is defined, you can create objects (instances) of it.
int main() {
    Student s1;   // Object creation
    s1.name = "Vivek";
    s1.age = 22;
    s1.display();
    return 0;
}

Output:
Name: Vivek, Age: 22

1.3 Accessing Class Members
Use the dot operator (.) for accessing members through an object.
Use the arrow operator (->) when working with pointers.
Example with pointer:
Student *s2 = new Student();
s2->name = "Riya";
s2->age = 20;
s2->display();
delete s2;  // free memory

📝 Practice Task 1
Create a Car class with attributes brand, model, and year.
Write a function to display car details.
Create two car objects and display their details.

2. Constructors and Destructors
In C++, constructors and destructors are special member functions used to manage object lifecycle.
2.1 Constructors
A constructor is a special function that gets automatically called when an object is created.
Rules:
  • Has the same name as the class.
  • No return type.
  • Can be overloaded.
Example:
class Student {
public:
    string name;
    int age;
    // Constructor
    Student(string n, int a) {
        name = n;
        age = a;
    }
    void display() {
        cout << "Name: " << name << ", Age: " << age << endl;
    }
};
int main() {
    Student s1("Ankit", 21);
    s1.display();
    return 0;
}

Output:
Name: Ankit, Age: 21

2.2 Types of Constructors
  • Default Constructor – Takes no arguments.
  • Parameterized Constructor – Takes parameters to initialize objects.
  • Copy Constructor – Creates a copy of an existing object.
Copy Constructor Example:
class Student {
public:
    string name;
    int age;
    Student(string n, int a) {
        name = n;
        age = a;
    }
    // Copy constructor
    Student(const Student &s) {
        name = s.name;
        age = s.age;
    }
    void display() {
        cout << name << " " << age << endl;
    }
};
int main() {
    Student s1("Ravi", 20);
    Student s2 = s1;  // copy constructor called
    s2.display();
}

2.3 Destructors
A destructor is a special function automatically invoked when an object is destroyed.

Rules:
  • Has the same name as the class but prefixed with ~.
  • No return type.
  • Cannot be overloaded.
Example:
class Test {
public:
    Test() { cout << "Constructor called" << endl; }
    ~Test() { cout << "Destructor called" << endl; }
};
int main() {
    Test t1;   // Constructor called here
}   // Destructor automatically called here

Output:
Constructor called
Destructor called

2.4 The This Pointer
This is an implicit pointer passed to every non-static member function. It refers to the current object.
Example:
class Student {
public:
    string name;
    int age;
    Student(string name, int age) {
        this->name = name;
        this->age = age;
    }
    void show() {
        cout << "Name: " << name << ", Age: " << age << endl;
    }
};
int main() {
    Student s("Pooja", 23);
    s.show();
}

📝 Practice Task 2
Write a program with a Book class that uses a parameterized constructor.
Implement a copy constructor for the same class.
Print messages from the destructor when objects are destroyed.

3. Static Data Members and Static Member Functions
Sometimes, you want a variable to be shared among all objects of a class rather than having separate copies. This is where static comes into play.

3.1 Static Data Members
  • Declared inside the class with the static keyword.
  • Shared by all objects.
  • Must be defined outside the class.
Example:
class Counter {
public:
    static int count;
    Counter() {
        count++;
    }
    void show() {
        cout << "Count: " << count << endl;
    }
};
// Definition of static member
int Counter::count = 0;
int main() {
    Counter c1, c2, c3;
    c1.show();
    c2.show();
    c3.show();
}

Output:
Count: 3
Count: 3
Count: 3

3.2 Static Member Functions
Can access only static members.
Do not need an object to be called.

Example:
class Test {
public:
    static int x;
    static void display() {
        cout << "Value of x: " << x << endl;
    }
};
int Test::x = 10;
int main() {
    Test::display();  // called without object
}

📝 Practice Task 3
Create a Bank class with a static variable to keep track of the number of accounts created.
Use a static function to display the count.

4. Friend Functions and Friend Classes
Sometimes, an external function or another class needs access to private members of a class. This is achieved through friend functions and friend classes.

4.1 Friend Function
Declared using the friend keyword.
Can access private and protected members of the class.

Example:
class Box {
private:
    int length;
public:
    Box(int l) { length = l; }
    friend void printLength(Box b);
};
void printLength(Box b) {
    cout << "Length: " << b.length << endl;
}
int main() {
    Box b(10);
    printLength(b);
}

4.2 Friend Class
The entire class can be declared as a friend.
Gives access to all private/protected members.

Example:
class A {
private:
    int data;
public:
    A() { data = 100; }
    friend class B;  // B is a friend class
};
class B {
public:
    void show(A a) {
        cout << "Data from class A: " << a.data << endl;
    }
};
int main() {
    A obj;
    B b;
    b.show(obj);
}

📝 Practice Task 4
Write a Circle class and a friend function to calculate the area.
Create two classes Employee and Company, make Company a friend of Employee.

5. Memory Management in C++
C++ gives manual control over memory allocation and deallocation.

5.1 Dynamic Memory Allocation
new keyword → Allocates memory.
delete keyword → Frees memory.

Example:
int *p = new int(5);
cout << *p << endl;  // 5
delete p;  // free memory

5.2 Dynamic Arrays
int *arr = new int[5];
for (int i = 0; i < 5; i++) arr[i] = i + 1;
for (int i = 0; i < 5; i++) cout << arr[i] << " ";
delete[] arr;  // free array memory

5.3 Common Memory Issues
  • Memory leaks – Forgetting to free allocated memory.
  • Dangling pointers – Using deleted memory.
  • Double free – Deleting memory twice.
📝 Practice Task 5
Create a dynamic array using new and input 5 integers.
Print them and then release memory using delete[].

6. Conclusion
Classes and Objects – Blueprints and instances.
Constructors and Destructors – For object lifecycle.
This pointer – Refers to the current object.
Static Members and Functions – Shared across objects.
Friend Functions and Friend Classes – For special access.
Memory Management – Using new and delete.
C++ equips developers with both power and responsibility. By mastering classes, objects, and memory management, you lay the foundation for advanced topics like inheritance, polymorphism, templates, and the STL (Standard Template Library).

🖥️ Dynamic Memory Allocation and Advanced Object-Oriented Programming in C++

C++ is one of the most powerful programming languages in existence, combining procedural programming from C with object-oriented programming (OOP) principles. While OOP concepts like classes, objects, inheritance, and polymorphism are central to C++, its unique strength lies in fine-grained memory management.
  • Dynamic memory allocation in C++ using new and delete.
  • Array of objects and their practical applications.
  • Object as function arguments (passing by value, reference, and pointer).
  • Returning objects from functions and its use cases.
  • Activities with step-by-step programs:
  1. Creating a C++ program with multiple classes and objects.
  2. Implementing constructor overloading in a C++ project.
  3. Using dynamic memory allocation to create and manage an array of objects.
  4. Writing a program demonstrating friend functions and static members.
By the end, you’ll not only understand these concepts but also implement real programs showcasing C++ power.

1. Dynamic Memory Allocation in C++
In C, we use malloc(), calloc(), realloc(), and free() for memory management. In C++, these are replaced by operators:
new → allocates memory.
delete → deallocates memory.
This provides a type-safe and object-oriented way of handling memory.

1.1 Using new
Syntax:
datatype *ptr = new datatype;       // single variable
datatype *arr = new datatype[size]; // array

Example:
#include <iostream>
using namespace std;
int main() {
    int *p = new int;   // allocate single int
    *p = 50;
    cout << "Value: " << *p << endl;
    delete p;   // free memory
    return 0;
}

Output:
Value: 50

1.2 Using delete
Whenever memory is allocated dynamically, it must be released using delete or delete[] (for arrays).
int *arr = new int[5];
for (int i = 0; i < 5; i++) arr[i] = i * 2;
for (int i = 0; i < 5; i++) cout << arr[i] << " ";
delete[] arr;  // free memory

Output:
0 2 4 6 8

1.3 Common Errors
  • Memory leaks → Forgetting to use delete.
  • Dangling pointer → Using pointer after delete.
  • Double delete → Freeing memory more than once.
💡 Best practice → Always pair every new with a delete.

2. Array of Objects in C++
An array of objects is a collection of instances of a class stored in continuous memory.
Example:
class Student {
public:
    string name;
    int age;
    void setData(string n, int a) {
        name = n;
        age = a;
    }
    void display() {
        cout << "Name: " << name << ", Age: " << age << endl;
    }
};
int main() {
    Student s[3];  // array of 3 objects
    s[0].setData("Amit", 20);
    s[1].setData("Riya", 22);
    s[2].setData("Vivek", 21);
    for (int i = 0; i < 3; i++) {
        s[i].display();
    }
}

Output:
Name: Amit, Age: 20
Name: Riya, Age: 22
Name: Vivek, Age: 21

3. Objects as Function Arguments
Objects can be passed to functions in three ways:
  • Pass by Value → A copy is passed (original remains unchanged).
  • Pass by Reference → Address/reference is passed (changes affect original).
  • Pass by Pointer → Using pointer variables.
Example: Pass by Value
class Box {
public:
    int length;
    Box(int l) { length = l; }
    void display() { cout << "Length: " << length << endl; }
};
void modify(Box b) {
    b.length = 100;
}
int main() {
    Box b1(20);
    modify(b1);
    b1.display();  // unchanged
}

Output:
Length: 20

Example: Pass by Reference
void modify(Box &b) {
    b.length = 100;
}

Now the original object changes.
Output:
Length: 100

4. Returning Objects from Functions
Functions can return objects just like primitive data types.
Example:
class Complex {
public:
    int real, imag;
    Complex(int r=0, int i=0) { real = r; imag = i; }
    Complex add(Complex c2) {
        Complex temp;
        temp.real = real + c2.real;
        temp.imag = imag + c2.imag;
        return temp;   // returning object
    }
    void display() {
        cout << real << " + " << imag << "i" << endl;
    }
};
int main() {
    Complex c1(3, 4), c2(2, 5), c3;
    c3 = c1.add(c2);
    c3.display();
}

Output:
5 + 9i

5. Activities with Programs
Now, let’s implement the given hands-on activities.
🏆 Activity 1: Create a C++ Program with Multiple Classes and Objects
#include <iostream>
using namespace std;
class Student {
public:
    string name;
    int roll;
    void setData(string n, int r) {
        name = n;
        roll = r;
    }
    void display() {
        cout << "Student: " << name << ", Roll: " << roll << endl;
    }
};
class Course {
public:
    string courseName;
    Course(string cname) {
        courseName = cname;
    }
    void showCourse() {
        cout << "Course: " << courseName << endl;
    }
};
int main() {
    Student s1, s2;
    s1.setData("Amit", 101);
    s2.setData("Riya", 102);
    Course c1("Computer Science");
    s1.display();
    s2.display();
    c1.showCourse();
}

Output:
Student: Amit, Roll: 101
Student: Riya, Roll: 102
Course: Computer Science

🏆 Activity 2: Implement Constructor Overloading in a C++ Project
class Rectangle {
public:
    int length, breadth;
    // Default constructor
    Rectangle() {
        length = 0; breadth = 0;
    }
    // Parameterized constructor
    Rectangle(int l, int b) {
        length = l; breadth = b;
    }
    // Copy constructor
    Rectangle(const Rectangle &r) {
        length = r.length;
        breadth = r.breadth;
    }
    void area() {
        cout << "Area: " << length * breadth << endl;
    }
};
int main() {
    Rectangle r1;          // default
    Rectangle r2(10, 5);   // parameterized
    Rectangle r3 = r2;     // copy
    r1.area();
    r2.area();
    r3.area();
}

🏆 Activity 3: Use Dynamic Memory Allocation for Array of Objects
class Employee {
public:
    string name;
    int id;
    void setData(string n, int i) {
        name = n; id = i;
    }
    void display() {
        cout << "Employee: " << name << ", ID: " << id << endl;
    }
};
int main() {
    int n;
    cout << "Enter number of employees: ";
    cin >> n;
    Employee *e = new Employee[n];  // dynamic array of objects
    for (int i = 0; i < n; i++) {
        string name; int id;
        cout << "Enter name and id: ";
        cin >> name >> id;
        e[i].setData(name, id);
    }
    cout << "\nEmployee List:\n";
    for (int i = 0; i < n; i++) {
        e[i].display();
    }
    delete[] e;  // free memory
}

🏆 Activity 4: Program Demonstrating Friend Functions and Static Members
class BankAccount {
private:
    string name;
    double balance;
    static int count;  // static variable
public:
    BankAccount(string n, double b) {
        name = n;
        balance = b;
        count++;
    }
    // friend function
    friend void showBalance(BankAccount acc);
    static void showCount() {
        cout << "Total Accounts: " << count << endl;
    }
};
int BankAccount::count = 0;
void showBalance(BankAccount acc) {
    cout << acc.name << " has balance: " << acc.balance << endl;
}
int main() {
    BankAccount a1("Riya", 5000);
    BankAccount a2("Amit", 3000);
    showBalance(a1);
    showBalance(a2);
    BankAccount::showCount();
}

Output:
Riya has balance: 5000
Amit has balance: 3000
Total Accounts: 2

6. Conclusion
We explored some of the most practical and advanced OOP concepts in C++:
Dynamic memory allocation using new and delete.
An array of objects and why they are useful in real-world programs.
Objects as function arguments (value, reference, and pointer).
Returning objects for modular, reusable design.
Friend functions and static members for controlled access and shared resources.
Along with these, we practiced four major coding activities, giving you a solid hands-on foundation.
By mastering these concepts, you move closer to real-world application development in C++, such as:
  • Inventory systems
  • Banking applications
  • Game engines
  • Scientific simulations

Comments